// ============================================================================
// FileName: AssemblyStateProxy.cs
//
// Description:
// Holds application configuration information.
//
// Author(s):
// Aaron Clauson
//
// History:
// 20 jan 2006	Aaron Clauson	Created.
//
// License: 
// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2006 Aaron Clauson (aaronc@blueface.ie), Blue Face Ltd, Dublin, Ireland (www.blueface.ie)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd. 
// nor the names of its contributors may be used to endorse or promote products derived from this software without specific 
// prior written permission. 
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
// ============================================================================

using System;
using System.Configuration;
using System.Net;
using CN.Sys;
using CN.Sys.Net;
using CN.VoIP.Net;
using CN.VoIP.Net.SIP;
using log4net;

namespace CNSIPSwitch
{
	/// <summary>
	/// This class maintains static application configuration settings that can be used by all classes within
	/// the AppDomain. This class is the one stop shop for retrieving or accessing application configuration settings.
	/// </summary>
	public class AssemblyStateProxy
	{
		public const int DEFAULT_PROXY_PORT = SIPConstants.DEFAULT_SIP_PORT;
        public const int NATKEEPALIVE_DEFAULTSEND_INTERVAL = 15;
        public const string LOGGER_NAME = "obelisk";

		public const string RUNTIME_CONFIG_FILE = "RuntimeConfigFile";
		public const string PROXY_IPADDRESS_KEY = "ProxyIPAddress";
		public const string PROXY_IPPORT_KEY = "ProxyPort";
        public const string MONITOR_LISTENPORT_KEY = "MonitorListenPort";
		public const string MONITOR_EVENTPORT_KEY = "MonitorEventPort";
        public const string PROXY_DBLOGTYPE_KEY = "ProxyLogStorageType";
        public const string PROXY_DBLOGCONNSTRKEY = "ProxyLogDBConnStr";
        public const string REGISTRAR_REALM_KEY = "RegistrarRealm";
        public const string PROXY_DOMAIN_KEY = "ProxyDomain";
        public const string REGISTRAR_CONTACTSPERUSER_KEY = "RegistrarContactsPerUser";
        public const string REGISTRAR_MAXEXPIRY_KEY = "RegistrarMaxExpiry";
        public const string STUN_SECONDARYSOCKET_KEY = "STUNSecondarySocket";
        public const string NATKEEPALIVE_LISTENERSOCKET_KEY = "NATKeepAliveListenerSocket";
        public const string NATKEEPALIVE_SENDINTERVAL_KEY = "NATKeepAliveSendInterval";

		public static ILog logger = null;

		public static readonly string RuntimeConfigFile;			// The file path to load the runtime config from.
		public static readonly int MonitorListenPort = 0;			// Public socket port the proxy monitor will listen on for client connections.
        public static readonly int MonitorEventPort = 0;			// Loopback port this process will listen on for monitor agents.

		public static readonly IPEndPoint ProxyIPEndPoint;				// Socket address the proxy will listen on.
		public static readonly bool ProxyLogging = false;				// Whether or not SIP messages flowing through the proxy should be logged.
		public static readonly IPEndPoint ProxyContactEndPoint;			// Socket address the proxy will use in Record-Route headers.	

        public static readonly StorageTypes ProxyLogStorageType;        // If DB logging of proxy events is being used this is the DB storage type.
        public static readonly string ProxyLogDBConnStr;                // If DB logging of proxy events is being used this is the DB connection string.

        public static readonly string RegistrarRealm;

        public static readonly int RegistrarContactsPerUser = 1;        // Number of contacts the registrar will maintain per user.
        public static readonly int RegistrarMaxExpiry = 0;

        public static readonly IPEndPoint STUNSecondaryEndPoint;

        public static readonly IPEndPoint NATKeepAliveListenerEndPoint;
        public static readonly int NATKeepAliveSendInterval = NATKEEPALIVE_DEFAULTSEND_INTERVAL;


		static AssemblyStateProxy()
		{
			try
			{
				RuntimeConfigFile = ConfigurationManager.AppSettings[RUNTIME_CONFIG_FILE];
                string ipAddress = ConfigurationManager.AppSettings[PROXY_IPADDRESS_KEY];
                string ipPort = ConfigurationManager.AppSettings[PROXY_IPPORT_KEY];
                string monitorListenPort = ConfigurationManager.AppSettings[MONITOR_LISTENPORT_KEY];
                string monitorEventPort = ConfigurationManager.AppSettings[MONITOR_EVENTPORT_KEY];
                string proxyDBLogTypeStr = ConfigurationManager.AppSettings[PROXY_DBLOGTYPE_KEY];
                ProxyLogDBConnStr = ConfigurationManager.AppSettings[PROXY_DBLOGCONNSTRKEY];
                RegistrarRealm = ConfigurationManager.AppSettings[PROXY_DOMAIN_KEY];
                string regContactsPerUserStr = ConfigurationManager.AppSettings[REGISTRAR_CONTACTSPERUSER_KEY];
                string regMaxExpiryStr = ConfigurationManager.AppSettings[REGISTRAR_MAXEXPIRY_KEY];
                string stunSocketPort = ConfigurationManager.AppSettings[STUN_SECONDARYSOCKET_KEY];
                string natKeepAliveSocketPort = ConfigurationManager.AppSettings[NATKEEPALIVE_LISTENERSOCKET_KEY];
                string natKeepAliveIntervalStr = ConfigurationManager.AppSettings[NATKEEPALIVE_SENDINTERVAL_KEY];

				try
				{
					// Configure logging.
					log4net.Config.XmlConfigurator.Configure();
					logger = log4net.LogManager.GetLogger(LOGGER_NAME);
				}
				catch(Exception excp)
				{
					Console.WriteLine("Exception AppState: " + excp.Message);
				}

				// Proxy Socket.
				int proxyIPPort = DEFAULT_PROXY_PORT;

				if(ipPort != null && ipPort.Trim().Length > 0)
				{
					try
					{
						proxyIPPort = Convert.ToInt32(ipPort);
					}
					catch{}
				}
					
				if(ipAddress == null || ipAddress.Trim().Length == 0)
				{
                    IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
                    string sIP = string.Empty;
                    IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
                    foreach (var ip in localIPs)
                    {
                        if (IPAddress.IsLoopback(ip)) continue;

                        if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                            continue;

                        if (SIPTransport.IsPrivateAddress(ip.ToString()))
                            continue;

                        if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                            ipAddress = ip.ToString();
                    }
                    ProxyIPEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), proxyIPPort);
				}
				else
				{
                    ProxyIPEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), proxyIPPort);
				}

				// Monitor Listen Port.
				try
				{
					if(monitorListenPort != null && monitorListenPort.Trim().Length > 0)
					{
						MonitorListenPort = Convert.ToInt32(monitorListenPort);
					}
				}
				catch
				{
					logger.Warn("The MonitorListenPort provided was not a valid integer.");
				}

                // Monitor Event Port.
                try
                {
                    if (monitorEventPort != null && monitorEventPort.Trim().Length > 0)
                    {
                        MonitorEventPort = Convert.ToInt32(monitorEventPort);
                    }
                }
                catch
                {
                    logger.Warn("The MonitorEventPort provided was not a valid integer.");
                }

                ProxyLogStorageType = StorageTypesConverter.GetStorageType(proxyDBLogTypeStr);

                //Registrar contacts per user.
                try
                {
                    if (regContactsPerUserStr != null && regContactsPerUserStr.Trim().Length > 0)
                    {
                        RegistrarContactsPerUser = Convert.ToInt32(regContactsPerUserStr);

                        if (RegistrarContactsPerUser <= 0)
                        {
                            RegistrarContactsPerUser = 1;
                        }
                    }
                }
                catch
                {
                    logger.Warn("The RegistrarContactsPerUser provided was not a valid integer.");
                }

                // Registrar Max Expiry.
                try
                {
                    if (regMaxExpiryStr != null && regMaxExpiryStr.Trim().Length > 0)
                    {
                        RegistrarMaxExpiry = Convert.ToInt32(regMaxExpiryStr);
                    }
                }
                catch
                {
                    logger.Warn("The RegistrarMaxExpiry value provided was not a valid integer.");
                }

                try
                {
                    int stunPort = Convert.ToInt32(stunSocketPort);
                    STUNSecondaryEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), stunPort);//IPSocket.ParseSocketString(stunSecondarySocketStr);
                }
                catch 
                {
                    throw new ApplicationException("The STUNSecondarySocket value was missing or invalid, needs to be in form 127.0.0.1:1234.");
                }

                try
                {
                    int natKeepAlivePort = Convert.ToInt32(natKeepAliveSocketPort);
                    NATKeepAliveListenerEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), natKeepAlivePort);//IPSocket.ParseSocketString(natKeepAliveSocketStr);
                }
                catch (Exception natKeepaliveExcp)
                {
                    logger.Warn("The " + NATKEEPALIVE_LISTENERSOCKET_KEY + " value was missing or invalid, needs to be in form 127.0.0.1:1234. " + natKeepaliveExcp.Message);
                }

                // NATKeepAlive send interval.
                try
                {
                    if (natKeepAliveIntervalStr != null && natKeepAliveIntervalStr.Trim().Length > 0)
                    {
                        NATKeepAliveSendInterval = Convert.ToInt32(natKeepAliveIntervalStr);
                    }
                }
                catch
                {
                    logger.Warn("The NATKeepAliveSendInterval value provided was not a valid integer.");
                }
			}
			catch(Exception excp)
			{
				logger.Error("Exception AssemblyStateProxy. " + excp.Message);
				//Console.WriteLine("Exception AssemblyStateProxy. " + excp.Message);	// In case the logging configuration is what caused the exception.
				throw excp;
			}
		}
	}
}